home *** CD-ROM | disk | FTP | other *** search
/ Sound Fx / Sound Fx.iso / Software / UNZIPED / MPW181-5 / _SETUP.1 / mci_obuf.cpp < prev    next >
C/C++ Source or Header  |  1997-04-21  |  9KB  |  374 lines

  1. /* mci_obuf.cpp
  2.  
  3.     Output buffer class for Win32 multimedia system written by
  4.    Jeff Tsay (ctsay@pasteur.eecs.berkeley.edu
  5.  
  6.    This program is free software; you can redistribute it and/or modify
  7.    it under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2 of the License, or
  9.    (at your option) any later version.
  10.  
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  19.  
  20. /* Writing to Windows multimedia system with such a small
  21.     buffer won't do, so we increase buffer size, and ignore
  22.     most of the writes. Also we need to have a queue of 3 wave
  23.     headers for smooth playback. The last header and the oldest
  24.     header play while the current one is being filled in.
  25.  
  26.     Note that this does not support 8-bit soundcards yet! I don't
  27.     know what the data format is to that */
  28.  
  29. /* Changes since last version: changed GMEM_MOVEABLE to GMEM_FIXED
  30.     which is a bit faster, according to the suggestions of Paul Forgey.
  31.     clear_buffer() added for seeking. Changes int16 parameter to int32
  32.     for minor speed improvement. Last edit: 06/29/96. */
  33.  
  34. /* More changes: eliminated GlobalLock on the fixed memory, which
  35.    is unnecessary.
  36.  
  37.    Added a function clear_buffer(), which clears the audio data
  38.    when a seek is made by the user.
  39.  
  40.    Also added a function set_stop_flag() which
  41.    sets a flag when playback is interrupted by the user. Then
  42.    no attempt is made to unprepare headers after waveReset() is
  43.    called by the main thread.
  44.  
  45.    Last edit: 10/12/96. */
  46.  
  47. /* Replaced usage of the PCMWAVEFORMAT structure with the more up
  48.    to date WAVEFORMATEX structure.
  49.  
  50.    According to the suggestions of Sergey Kuzmin, replaced
  51.    GlobalAlloc and GlobalFree with new and delete, which should
  52.    eliminate memory leaks.
  53.  
  54.    Last edit: 12/31/96. */
  55.  
  56. #ifdef  __WIN32__
  57. #define STRICT
  58. #define WIN32_LEAN_AND_MEAN
  59. #define NOMCX
  60. #define NOIME
  61. #define NOGDI
  62. #define NOUSER
  63. #define NOSOUND
  64. #define NOCOMM
  65. #define NODRIVERS
  66. #define OEMRESOURCE
  67. #define NONLS
  68. #define NOSERVICE
  69. #define NOKANJI
  70. #define NOMINMAX
  71. #define NOLOGERROR
  72. #define NOPROFILER
  73. #define NOMEMMGR
  74. #define NOLFILEIO
  75. #define NOOPENFILE
  76. #define NORESOURCE
  77. #define NOATOM
  78. #define NOLANGUAGE
  79. #define NOLSTRING
  80. #define NODBCS
  81. #define NOKEYBOARDINFO
  82. #define NOGDICAPMASKS
  83. #define NOCOLOR
  84. #define NOGDIOBJ
  85. #define NODRAWTEXT
  86. #define NOTEXTMETRIC
  87. #define NOSCALABLEFONT
  88. #define NOBITMAP
  89. #define NORASTEROPS
  90. #define NOMETAFILE
  91. #define NOSYSMETRICS
  92. #define NOSYSTEMPARAMSINFO
  93. #define NOMSG
  94. #define NOWINSTYLES
  95. #define NOWINOFFSETS
  96. #define NOSHOWWINDOW
  97. #define NODEFERWINDOWPOS
  98. #define NOVIRTUALKEYCODES
  99. #define NOKEYSTATES
  100. #define NOWH
  101. #define NOMENUS
  102. #define NOSCROLL
  103. #define NOCLIPBOARD
  104. #define NOICONS
  105. #define NOMB
  106. #define NOSYSCOMMANDS
  107. #define NOMDI
  108. #define NOCTLMGR
  109. #define NOWINMESSAGES
  110. #define NOHELP
  111. #define _WINUSER_
  112. #define __oleidl_h__
  113. #define _OLE2_H_
  114. #include <windows.h>
  115.  
  116. #ifndef WIN32GUI
  117. #include <iostream.h>
  118. #endif
  119.  
  120. #include "header.h"
  121. #include "args.h"
  122. #include "obuffer.h"
  123. #include "mci_obuf.h"
  124.  
  125. MCIbuffer::MCIbuffer(uint32 number_of_channels,
  126.                             MPEG_Args *maplay_args)
  127. {
  128.   channels  = number_of_channels;
  129.   data_size = channels * BUFFERSIZE;
  130.  
  131.   hdr_size      = sizeof(WAVEHDR);
  132.   lpwavehdr_arr = new LPWAVEHDR[3];
  133.   phwo          = maplay_args->phwo;
  134.   fillup        = 0;
  135.  
  136.   lpwf = (tWAVEFORMATEX *) new WAVEFORMATEX;
  137.  
  138.   lpwf->wBitsPerSample  = 16;  // No 8-bit support yet
  139.   lpwf->wFormatTag      = WAVE_FORMAT_PCM;
  140.   lpwf->nChannels       = (WORD) channels;
  141.   lpwf->nSamplesPerSec  = (DWORD) maplay_args->MPEGheader->frequency();
  142.   lpwf->nAvgBytesPerSec = (DWORD) channels *
  143.                                                maplay_args->MPEGheader->frequency() << 1;
  144.   lpwf->nBlockAlign     = (WORD) (channels << 1);
  145.   lpwf->cbSize          = 0;
  146.  
  147.   if (waveOutOpen(phwo, WAVE_MAPPER, (const tWAVEFORMATEX *) lpwf,
  148.                        NULL, NULL, WAVE_ALLOWSYNC) != MMSYSERR_NOERROR)
  149.   {
  150. #ifndef WIN32GUI
  151.         cerr << endl << "Could not open wave device." << endl;
  152. #endif
  153.         return;
  154.   }
  155.  
  156.   buffer_count = 0;
  157.  
  158.   for(uint32 i=0; i<3; i++) {
  159.       lpwavehdr_arr[i] = (LPWAVEHDR) new WAVEHDR;
  160.  
  161.      LPWAVEHDR temp = lpwavehdr_arr[i];
  162.  
  163.       if(!temp) return;
  164.  
  165.       temp->lpData = (LPSTR) new char[data_size];
  166.  
  167.       if(!temp->lpData) return;
  168.       temp->dwBufferLength  = data_size;
  169.       temp->dwBytesRecorded = 0;
  170.       temp->dwUser          = 0;  // If played, dwUser = 1
  171.       temp->dwLoops         = 0;
  172.       temp->dwFlags         = NULL;
  173.   }
  174.  
  175.   for(uint32 i=0; i<channels; i++)
  176.        bufferp[i] = i * channels;
  177.  
  178.   user_stop = 0;
  179. }
  180.  
  181. void MCIbuffer::append (uint32 channel, int16 value)
  182. {
  183.   // Need to break up the 32-bit integer into 2 8-bit bytes.
  184.   // (ignore the first two bytes - either 0x0000 or 0xffff)
  185.   // Note that Intel byte order is backwards!!!
  186.  
  187.   LPSTR temp = lpwavehdr_arr[2]->lpData;
  188.  
  189.   temp[bufferp[channel]]   = (char) (value & 0xff);
  190.   temp[bufferp[channel]+1] = (char) (value >> 8);
  191.  
  192.   bufferp[channel] += channels << 1;
  193.  
  194.   return;
  195. }
  196.  
  197. #pragma argsused
  198. void MCIbuffer::write_buffer(int32 fd)
  199. {
  200.     // Actually write only when buffer is actually full.
  201.     if ((++buffer_count & BIT_SELECT) == 0) {
  202.  
  203.         buffer_count = 0;
  204.  
  205.         // Wait for 2 completed headers
  206.         if (fillup > 1) {
  207.  
  208.             // Prepare & write newest header
  209.             waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
  210.             waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
  211.  
  212.             // Header has now been sent
  213.             lpwavehdr_arr[2]->dwUser = 1;
  214.  
  215.             wave_swap();
  216.  
  217.             // Unprepare oldest header
  218.             if (lpwavehdr_arr[2]->dwUser) {
  219.  
  220.                 while(waveOutUnprepareHeader(*phwo, lpwavehdr_arr[2],
  221.                        hdr_size) == WAVERR_STILLPLAYING)
  222.                     Sleep(SLEEPTIME);
  223.             }
  224.  
  225.         } else {
  226.  
  227.             if (++fillup == 2) {
  228.  
  229.                     // Write the previously calculated 2 headers
  230.                     waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  231.                     waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  232.  
  233.                     // Header has now been sent
  234.                     lpwavehdr_arr[0]->dwUser = 1;
  235.  
  236.                     wave_swap();
  237.  
  238.                     waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  239.                     waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  240.  
  241.                     // Header has now been sent
  242.                     lpwavehdr_arr[0]->dwUser = 1;
  243.  
  244.             } else {
  245.                 wave_swap();
  246.          }
  247.         }
  248.  
  249.         for(uint32 i=0; i<channels; i++)
  250.           bufferp[i] = i * channels;
  251.     }
  252.     return;
  253. }
  254.  
  255. void MCIbuffer::wave_swap()
  256. {
  257.     LPWAVEHDR temp   = lpwavehdr_arr[2];
  258.    lpwavehdr_arr[2] = lpwavehdr_arr[1];
  259.    lpwavehdr_arr[1] = lpwavehdr_arr[0];
  260.     lpwavehdr_arr[0] = temp;
  261.  
  262.     return;
  263. }
  264.  
  265. #ifdef SEEK_STOP
  266. void MCIbuffer::clear_buffer()
  267. // Clear all the data in the buffers
  268. {
  269.  
  270.     waveOutReset(*phwo);
  271.  
  272.     for(uint32 i=0; i<3; i++) {
  273.  
  274.         LPWAVEHDR temp = lpwavehdr_arr[i];
  275.  
  276.         if (temp->dwUser)
  277.             waveOutUnprepareHeader(*phwo, temp, hdr_size);
  278.  
  279.         temp->dwUser = 0;
  280.  
  281.         for(uint32 j=0; j<data_size; j++)
  282.             temp->lpData[j] = (char) 0;
  283.     }
  284.  
  285.     // Reset buffer pointers
  286.     for(uint32 i=0; i<channels; i++)
  287.         bufferp[i] = i * channels;
  288.  
  289.     // Force the buffers to fillup before playing.
  290.     fillup = buffer_count = 0;
  291. }
  292.  
  293. void MCIbuffer::set_stop_flag()
  294. // Set the flag to avoid unpreparing non-existent headers
  295. {
  296.     user_stop = 1;
  297.    return;
  298. }
  299. #endif
  300.  
  301.  
  302. MCIbuffer::~MCIbuffer()
  303. {
  304.    if (user_stop) {
  305.  
  306.      waveOutReset(*phwo);
  307.  
  308.    } else {
  309.  
  310.        if (fillup == 1) {
  311.  
  312.            // Write the last header calculated (at the top of the array).
  313.            waveOutPrepareHeader(*phwo, lpwavehdr_arr[0], hdr_size);
  314.              waveOutWrite(*phwo, lpwavehdr_arr[0], hdr_size);
  315.  
  316.          // Header has been written.
  317.            lpwavehdr_arr[0]->dwUser = 1;
  318.       }
  319.  
  320.       if (buffer_count) {
  321.  
  322.           /* Write the last wave header (probably not be written due to buffer size
  323.               increase.) */
  324.  
  325.          for(uint32 i = bufferp[channels-1]; i < data_size; i++)
  326.                  lpwavehdr_arr[2]->lpData[i] = (char) 0;
  327.  
  328.            waveOutPrepareHeader(*phwo, lpwavehdr_arr[2], hdr_size);
  329.             waveOutWrite(*phwo, lpwavehdr_arr[2], hdr_size);
  330.  
  331.            // Header has been written.
  332.          lpwavehdr_arr[2]->dwUser = 1;
  333.          wave_swap();
  334.          }
  335.    }
  336.  
  337.     // Unprepare and free the header memory.
  338.     for (int32 j=2; j>=0; j--) {
  339.           if (lpwavehdr_arr[j]->dwUser && !user_stop)
  340.             while (waveOutUnprepareHeader(*phwo, lpwavehdr_arr[j], hdr_size)
  341.                   == WAVERR_STILLPLAYING)
  342.                 Sleep(SLEEPTIME);
  343.  
  344.       delete [] lpwavehdr_arr[j]->lpData;
  345.       delete lpwavehdr_arr[j];
  346.     }
  347.  
  348.    delete [] lpwavehdr_arr;
  349.     delete lpwf;
  350.  
  351.  
  352.     while(waveOutClose(*phwo) == WAVERR_STILLPLAYING);
  353.         Sleep(SLEEPTIME);
  354.  
  355.     return;
  356. }
  357.  
  358. Obuffer *create_obuffer(MPEG_Args *maplay_args)
  359. {
  360.     Obuffer *buffer;
  361.  
  362.     enum e_mode mode = maplay_args->MPEGheader->mode();
  363.    enum e_channels which_channels = maplay_args->which_c;
  364.  
  365.     if ((mode == single_channel) || (which_channels != both))
  366.         buffer = new MCIbuffer(1, maplay_args);    // mono
  367.    else
  368.         buffer = new MCIbuffer(2, maplay_args);    // stereo
  369.  
  370.    return(buffer);
  371. }
  372.  
  373. #endif // __WIN32__
  374.